﻿using System.Text;
using Elsa.Expressions.Contracts;
using Elsa.Extensions;
using Elsa.Workflows;
using Elsa.Workflows.Attributes;
using Elsa.Workflows.Memory;
using Elsa.Workflows.UIHints;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Expression.Entity;
using T.FAS.Runtime.MF.Activities.Extensions;
using T.FAS.Runtime.MF.Dao;
using T.FAS.Runtime.MF.Entity;
using T.FAS.Runtime.MF.SPI;
using T.ServiceComponent.Kernel.Service;

namespace T.FAS.Runtime.MF.Activities
{
    public class DataQueryActivity : FASCodeActivity<object?>
    {
        [Elsa.Workflows.Attributes.Input(Description = "DataQuery的Code", UIHint = InputUIHints.SingleLine, Order = 1)]
        public string DataQueryName { get; set; }
        [Input(Description = "The cases to evaluate.", UIHint = "switch-editor", Order = 3)]
        public IList<BranchCondition> ParamList { get; set; }

        public List<Variable> ActivityOutputVariables { get { return OutputVariables != null ? OutputVariables.Values.ToList() : new List<Variable>(); } }
        /// <summary>
        /// 节点默认输出的变量
        /// </summary>
        //public List<Variable> OutputVariables { get; set; }
        public Dictionary<string, Variable> OutputVariables { get; set; }
        protected override async void Execute(ActivityExecutionContext context)
        {

            try
            {
                var scriptBuilder = await GetToExeuteScript(context);

                if (scriptBuilder.Length > 0)
                {

                    await ExecuteScript(context, scriptBuilder);
                }
            }
            catch (Exception ex)
            {
                await context.FaultAndComplete(ex, this);
            }
         
        }

        private async Task ExecuteScript(ActivityExecutionContext context,StringBuilder scriptBuilder)
        {
             //var expService1 = context.GetRequiredService<IFasExpService>();

            var factory = context.GetService<Func<string, IFasExpService>>();
            var expService = factory("publish");

            var extraParams = CallContext.GetData("WorkflowDebugParam");
            //调试模式
            if (extraParams != null)
            {
                expService = factory("debug");
            }


            var result = expService.Debug(scriptBuilder.ToString(), new Dictionary<string, object>(), extraParams != null ? (extraParams as Dictionary<string, string>) : null);
            var outputInstanceValues = new Dictionary<string, object>();
            if (result != null)
            {
                //成功
                if (result.State == Expression.Entity.ResultState.Success)
                {
                    var resultValue = ProcessResultValue(result);
                    if (resultValue==null)
                    {
                        var exception = new Exception("DQ返回空值为空");

                        await context.FaultAndComplete(exception, this);
                    }
                    LogUtil.Log($"DataQuery.result.Result.Type={result.Result.GetType()},result.Result as List<object>={result.Result as List<object>}");
                    LogUtil.Log($"DataQuery.result.resultValue={JsonConvert.SerializeObject(resultValue)}");
                   // LogUtil.Log($"DataQuery.result.resultValue={JsonConvert.SerializeObject(resultValue as List<object>)}");
                    context.SetResult(resultValue);
                   
                    foreach (var variableName in OutputVariables.Keys)
                    {
                        var variable = OutputVariables[variableName];
                        context.SetVariable(variable.Name, resultValue);

                        //向迭代返回值数组中赋值,这里会累计每次迭代的执行结果，返回到数组中
                        context.SetIterationVariableValue(variable.Name, resultValue);

                        //给输出参数赋值
                        outputInstanceValues[variableName] = resultValue;
                    }
                    this.OutputInstanceValues[context.Id] = outputInstanceValues;
                }
                else
                {
                    var exception = new Exception(result.ErrMsg);

                    await context.FaultAndComplete(exception, this);
                }
            }
        }
        private object[] ProcessResultValue(ExprResult result)
        {
            object[] resultValue = null;

            if (result.Result is JArray)
            {
                resultValue = (result.Result as JArray).ToStructuredObjectArray();
            }
            else if (result.Result is TArray<TRecord>)
            {
                JArray resultJArrays = new JArray();
                var resultRecords = result.Result as TArray<TRecord>;
                foreach (var record in resultRecords)
                {
                    resultJArrays.Add(TRecord.ToJson(record));
                }
                resultValue = resultJArrays.ToStructuredObjectArray();
            }
            else if (result.Result is TArray<JObject>)
            {
                var resultJArrays = new JArray();
                var resultRecords = result.Result as TArray<JObject>;
                foreach (var record in resultRecords)
                {
                    resultJArrays.Add(record);
                }
                resultValue = resultJArrays.ToStructuredObjectArray();
            }
            return resultValue;
        }
        private async Task<StringBuilder> GetToExeuteScript(ActivityExecutionContext context)
        {
            var scriptBuilder = new StringBuilder();
            var expressionEvaluator = context.GetRequiredService<IExpressionEvaluator>();
            var inputInstanceValues = new Dictionary<string, object>();

            foreach (var param in ParamList)
            {
                var conditionValue = await expressionEvaluator.EvaluateAsync<object>(param.Condition, context.ExpressionExecutionContext);
                if (conditionValue == null)
                {
                    scriptBuilder.AppendLine($"let {param.Label}=null;");
                }
                else
                {
                    if (conditionValue.GetType() == typeof(string))
                    {
                        scriptBuilder.AppendLine($"let {param.Label}='{conditionValue}';");
                    }
                    else
                    {
                        scriptBuilder.AppendLine($"let {param.Label}={conditionValue};");
                    }
                }
                inputInstanceValues[param.Label] = conditionValue;
            }
            this.InputInstanceValues[context.Id] = inputInstanceValues;

            scriptBuilder.AppendLine($"DataQuery.{DataQueryName}({string.Join(",", ParamList.Select(t => t.Label))}).List");
            return scriptBuilder;
        }
    }
}
